/*
 * Copyright (c) 2012 Travis Geiselbrecht
 *
 * Use of this source code is governed by a MIT-style
 * license that can be found in the LICENSE file or at
 * https://opensource.org/licenses/MIT
 */
#include <lk/debug.h>
#include <assert.h>
#include <dev/gpio.h>
#include <platform/lpc22xx.h>
#include <platform/gpio.h>


#define GPIOREG(base, reg)  (*REG32((base)  + (reg)))



void lpc22xx_gpio_early_init(void) {

}

int gpio_config(unsigned nr, unsigned flags) {

	unsigned int port = GPIO_PORT(nr);
	unsigned int pin = 1 << GPIO_PIN(nr);

    switch(port){
    case GPIO_PORT_0:
        if (flags & GPIO_INPUT) {
        	GPIOREG(LPC22XX_GPIO0_BASE, LPC22XX_GPIO_DIR_OFFSET) &= ~pin;
        } else if  (flags & GPIO_OUTPUT) {
        	GPIOREG(LPC22XX_GPIO0_BASE, LPC22XX_GPIO_DIR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_1:
        if (flags & GPIO_INPUT) {
        	GPIOREG(LPC22XX_GPIO1_BASE, LPC22XX_GPIO_DIR_OFFSET) &= ~pin;
        } else if  (flags & GPIO_OUTPUT) {
        	GPIOREG(LPC22XX_GPIO1_BASE, LPC22XX_GPIO_DIR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_2:
        if (flags & GPIO_INPUT) {
        	GPIOREG(LPC22XX_GPIO2_BASE, LPC22XX_GPIO_DIR_OFFSET) &= ~pin;
        } else if  (flags & GPIO_OUTPUT) {
        	GPIOREG(LPC22XX_GPIO2_BASE, LPC22XX_GPIO_DIR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_3:
        if (flags & GPIO_INPUT) {
        	GPIOREG(LPC22XX_GPIO3_BASE, LPC22XX_GPIO_DIR_OFFSET) &= ~pin;
        } else if  (flags & GPIO_OUTPUT) {
        	GPIOREG(LPC22XX_GPIO3_BASE, LPC22XX_GPIO_DIR_OFFSET) |= pin;
        }
    	break;
    default:
    	break;
    }

    return 0;
}

void gpio_set(unsigned nr, unsigned on) {
	unsigned int port = GPIO_PORT(nr);
	unsigned int pin = 1 << GPIO_PIN(nr);

    switch(port){
    case GPIO_PORT_0:
        if (on) {
        	GPIOREG(LPC22XX_GPIO0_BASE, LPC22XX_GPIO_SET_OFFSET) |= pin;
        } else {
        	GPIOREG(LPC22XX_GPIO0_BASE, LPC22XX_GPIO_CLR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_1:
        if (on) {
        	GPIOREG(LPC22XX_GPIO1_BASE, LPC22XX_GPIO_SET_OFFSET) |= pin;
        } else {
        	GPIOREG(LPC22XX_GPIO1_BASE, LPC22XX_GPIO_CLR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_2:
        if (on) {
        	GPIOREG(LPC22XX_GPIO2_BASE, LPC22XX_GPIO_SET_OFFSET) |= pin;
        } else {
        	GPIOREG(LPC22XX_GPIO2_BASE, LPC22XX_GPIO_CLR_OFFSET) |= pin;
        }
    	break;
    case GPIO_PORT_3:
        if (on) {
        	GPIOREG(LPC22XX_GPIO3_BASE, LPC22XX_GPIO_SET_OFFSET) |= pin;
        } else {
        	GPIOREG(LPC22XX_GPIO3_BASE, LPC22XX_GPIO_CLR_OFFSET) |= pin;
        }
    	break;
    default:
    	break;
    }
}

int gpio_get(unsigned nr) {
	unsigned int port = GPIO_PORT(nr);
	unsigned int pin = 1 << GPIO_PIN(nr);
	int value = 0;

    switch(port){
    case GPIO_PORT_0:
        if ((GPIOREG(LPC22XX_GPIO0_BASE, LPC22XX_GPIO_PIN_OFFSET) & pin ) == 0) {
        	value = 0;
        } else {
        	value = 1;
        }
    	break;
    case GPIO_PORT_1:
        if ((GPIOREG(LPC22XX_GPIO1_BASE, LPC22XX_GPIO_PIN_OFFSET) & pin ) == 0) {
        	value = 0;
        } else {
        	value = 1;
        }
    	break;
    case GPIO_PORT_2:
        if ((GPIOREG(LPC22XX_GPIO2_BASE, LPC22XX_GPIO_PIN_OFFSET) & pin ) == 0) {
        	value = 0;
        } else {
        	value = 1;
        }
    	break;
    case GPIO_PORT_3:
        if ((GPIOREG(LPC22XX_GPIO3_BASE, LPC22XX_GPIO_PIN_OFFSET) & pin ) == 0) {
        	value = 0;
        } else {
        	value = 1;
        }
    	break;
    default:
    	break;
    }

    return value;
}

